/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "yyjson_util.h"
#include "json_error.h"
#include <vector>

using namespace json_error;

bool yyjson_util::is_valid_integer(const char *val, size_t len) {
    bool is_positive_integer = true;
    if (val[0] != '\0') {
        // 检查第一个字符：不能为0（除非是单个字符'0'，但0不是正整数）
        if (val[0] == '0' && len > 1) {
            // 如果第一个字符是0且字符串长度>1，说明有前导0（如"012"），无效
            // 或者字符串就是"0"，但0不是正整数
            // 跳过处理
            is_positive_integer = false;
        } else {
            // 遍历所有字符，确保都是数字（0-9）
            for (const char *p = val; *p != '\0'; p++) {
                if (*p < '0' || *p > '9') {
                    is_positive_integer = false;
                    break;
                }
            }
        }
    } else {
        is_positive_integer = false;
    }
    return is_positive_integer;
}

char* yyjson_util::add_prefix(const char *key_str, size_t len) {
    char *new_key = new char[len + 5];
    new_key[0] = '_';
    new_key[1] = 'Y';
    new_key[2] = 'Y';
    new_key[3] = '_';
    std::memcpy(new_key + 4, key_str, len + 1); // 复制原字符串+终止符
    return new_key;
}

napi_value yyjson_util::yyjson_to_napi(struct napi_env__ *env, yyjson_val *val) {
    napi_value result = nullptr;
    // 根据类型处理值
    if (yyjson_is_obj(val)) {
        // 准备属性描述符数组
        std::vector<const char *> keys;
        std::vector<napi_value> values;
        keys.reserve(unsafe_yyjson_get_len(val));
        values.reserve(keys.size());
        size_t idx, max;
        yyjson_val *key, *value;

        yyjson_obj_foreach(val, idx, max, key, value) {
            const char *key_str = unsafe_yyjson_get_str(key);
            size_t len = strlen(key_str);
            if (is_valid_integer(key_str, len)) {
                char *new_key = add_prefix(key_str, len);
                keys.push_back(new_key);
            } else {
                keys.push_back(key_str);
            }
            values.push_back(yyjson_to_napi(env, value));
        }
        handleNapiError(env, napi_create_object_with_named_properties(env, &result, keys.size(), 
                                                                      keys.data(), values.data()));
    } else if (yyjson_is_arr(val)) {
        handleNapiError(env, napi_create_array_with_length(env, unsafe_yyjson_get_len(val), &result));
        size_t idx, max;
        yyjson_val *value;
        yyjson_arr_foreach(val, idx, max, value) {
            napi_value res = yyjson_to_napi(env, value);
            handleNapiError(env, napi_set_element(env, result, idx, res));
        }
    } else if (yyjson_is_str(val)) {
        handleNapiError(env, napi_create_string_utf8(env, unsafe_yyjson_get_str(val), NAPI_AUTO_LENGTH, &result));
    } else if (yyjson_is_uint(val)) {
        handleNapiError(env, napi_create_bigint_uint64(env, unsafe_yyjson_get_uint(val), &result));
    } else if (yyjson_is_sint(val)) {
        handleNapiError(env, napi_create_bigint_int64(env, unsafe_yyjson_get_sint(val), &result));
    } else if (yyjson_is_num(val)) {
        handleNapiError(env, napi_create_double(env, unsafe_yyjson_get_num(val), &result));
    } else if (yyjson_is_bool(val)) {
        handleNapiError(env, napi_get_boolean(env, unsafe_yyjson_get_bool(val), &result));
    }
    return result;
}

yyjson_mut_val* yyjson_util::napi_to_yyjson(napi_env env, yyjson_mut_doc* doc, napi_value value) {
    napi_valuetype type;
    napi_typeof(env, value, &type);

    switch (type) {     
        case napi_undefined:
            return yyjson_mut_null(doc);
        case napi_null:
            return yyjson_mut_null(doc);
        case napi_boolean: {
            bool b;
            handleNapiError(env, napi_get_value_bool(env, value, &b));
            return yyjson_mut_bool(doc, b);
        }
        case napi_number: {
            double num;
            handleNapiError(env, napi_get_value_double(env, value, &num));
            return yyjson_mut_real(doc, num);
        }
        case napi_bigint: {
            bool lossless;
            int64_t i64;
            handleNapiError(env, napi_get_value_bigint_int64(env, value, &i64, &lossless));
            if (lossless) {
                return yyjson_mut_sint(doc, i64);
            } else {
                // If not lossless or conversion failed, convert to string representation
                napi_value str_val;
                handleNapiError(env, napi_coerce_to_string(env, value, &str_val));
                
                size_t len;
                handleNapiError(env, napi_get_value_string_utf8(env, str_val, nullptr, 0, &len));
                std::vector<char> buf(len + 1);
                handleNapiError(env, napi_get_value_string_utf8(env, str_val, buf.data(), buf.size(), &len));
                return yyjson_mut_strncpy(doc, buf.data(), len);
            }
        }
        case napi_string: {
            size_t len;
            handleNapiError(env, napi_get_value_string_utf8(env, value, nullptr, 0, &len));
            std::vector<char> buf(len + 1);
            handleNapiError(env, napi_get_value_string_utf8(env, value, buf.data(), buf.size(), &len));
            return yyjson_mut_strncpy(doc, buf.data(), len);
        }
        case napi_object: {
            bool is_array;
            handleNapiError(env, napi_is_array(env, value, &is_array));
            
            if (is_array) {
                uint32_t length;
                handleNapiError(env, napi_get_array_length(env, value, &length));
                yyjson_mut_val* arr = yyjson_mut_arr(doc);
                
                for (uint32_t i = 0; i < length; i++) {
                    napi_value element;
                    handleNapiError(env, napi_get_element(env, value, i, &element));
                    yyjson_mut_val* val = napi_to_yyjson(env, doc, element);
                    yyjson_mut_arr_append(arr, val);
                }
                return arr;
            } else {
                yyjson_mut_val* obj = yyjson_mut_obj(doc);
                napi_value properties;
                handleNapiError(env, napi_get_property_names(env, value, &properties));
                
                uint32_t length;
                handleNapiError(env, napi_get_array_length(env, properties, &length));
                
                for (uint32_t i = 0; i < length; i++) {
                    napi_value key;
                    handleNapiError(env, napi_get_element(env, properties, i, &key));
                    
                    size_t key_len;
                    handleNapiError(env, napi_get_value_string_utf8(env, key, nullptr, 0, &key_len));
                    std::vector<char> key_buf(key_len + 1);
                    handleNapiError(env, napi_get_value_string_utf8(env, key, key_buf.data(), key_buf.size(), &key_len));
                    
                    napi_value prop_value;
                    handleNapiError(env, napi_get_property(env, value, key, &prop_value));
                    
                    yyjson_mut_val* val = napi_to_yyjson(env, doc, prop_value);
                    yyjson_mut_obj_add(obj, yyjson_mut_strncpy(doc, key_buf.data(), key_len), val);
                }
                return obj;
            }
        }
        default:
            return yyjson_mut_null(doc);
    }
}